// prefetcher.bpf.c
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#include "prefetcher.h"

char LICENSE[] SEC("license") = "GPL";

// --- Maps ---
// V2: 只保留 Ring Buffer 和 Config Map
struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} events SEC(".maps");

struct {
    __uint(type, BPF_MAP_TYPE_ARRAY);
    __uint(max_entries, 1);
    __type(key, __u32);
    __type(value, struct config);
} config_map SEC(".maps");

// 定义 tracepoint 上下文的结构体 (保持不变)
struct page_fault_ctx {
    unsigned short common_type;
    unsigned char common_flags;
    unsigned char common_preempt_count;
    int common_pid;
    unsigned long address;
    unsigned long ip;
    unsigned long error_code;
};

#define PAGE_SIZE 4096

SEC("tracepoint/exceptions/page_fault_user")
int handle_page_fault(struct page_fault_ctx *ctx) {
    // 1. 获取当前进程/线程信息
    __u64 pid_tgid = bpf_get_current_pid_tgid();
    __u32 pid = pid_tgid >> 32;
    __u32 tid = (__u32)pid_tgid;

    // 2. 读取配置并过滤PID
    const __u32 key = 0;
    struct config *cfg = bpf_map_lookup_elem(&config_map, &key);
    if (!cfg) {
        return 0; // 不应该发生
    }
    if (cfg->target_pid != 0 && pid != cfg->target_pid) {
        return 0;
    }

    // 3. 获取缺页地址
    unsigned long addr = ctx->address;

    // 4. 预留 Ring Buffer 空间
    struct fault_info *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
    if (!e) {
        return 0; // 空间不足，丢弃事件
    }

    // 5. 填充原始数据
    e->pid = pid;
    e->tid = tid;
    e->addr = addr;

    // 6. 提交事件，用户态将处理所有逻辑
    bpf_ringbuf_submit(e, 0);

    return 0;
}